Auto-Refreshing Content List

Latest update: July 2013

In this tutorial, we will show you how to poll your FlashAir device contents and make your content list auto refresh. We will use thumbnail.cgi and command.cgi to do this.

We will set the content list we created in Android Tutorial 4: Getting Image Thumbnails to regularly check if the contents of the FlashAir have changed. If they have changed, the content list will update itself. This tutorial will take some of the commands learned in previous tutorials and use them to obtain or display data.

Note: To get the most out of this tutorial, we suggest that you insert your FlashAir device into a digital camera. When you take a new photo or delete a photo, this application will show the changed contents of the FlashAir device.

The list containing the file name and thumbnail pairs of the contents of your FlashAir device will be formatted like this:

This image shows the content list

If you insert your FlashAir device into a digital camera and take a photograph, the content list will refresh itself (after a designated interval of time) and will include the photo that you just took:

This image shows an updated content list

You will be able to click the name of the new image file and view the photo in a new screen:

This image shows the new image in an image view

As you are viewing the image, the image file will download to your Android device.

We will need to create the following files in order to write this application:

  • MainActivity.java
  • activity_main.xml
  • ImageViewActivity.java
  • activity_image_view.xml

Important: Please note that your project contains a file called AndroidManifest.xml. This file gives your application particular permissions. By default, applications are not permitted to access the internet. The path to this file should look something like: [Project_Folder]/AndroidManifest.xml
You will need to add the following lines of code into your AndroidManifest.xml in order for this application to work:

<uses-permission android:name="android.permission.INTERNET" />

Creating the List Layout

First, we will write the activity_main.xml file that determines the layout of our Android App. This can be found in your layout folder. The path to this file should look something like: [Project_Folder]/res/layout/activity_main.xml

This file will be identical to the activity_main.xml file from Android Tutorial 3: Downloading Content. Please refer to that tutorial for an explanation of the implementation.

Creating the Image Viewing Layout

Next, we will create the activity_image_view.xml file that determines the layout of our image viewing screen. This can also be found in your layout folder. The path to this file should look something like: [Project_Folder]/res/layout/activity_image_view.xml

This file will be identical to the activity_image_view.xml file from Android Tutorial 3: Downloading Content. Please refer to that tutorial for an explanation of the implementation.

Creating the Content List

First, we will get a list of the file names in the desired directory of your FlashAir device (see Android Tutorial 3: Downloading Content for a detailed explanation).

Then we will set each file name in the list to an associated thumbnail, display both the file name and thumbnail pair in a ListView format, and set the behavior of the list. For detailed explanation on the implementation, see Android Tutorial 4: Getting Image Thumbnails

Initialization

Please take the MainActivity.java code from Android Tutorial 4: Getting Image Thumbnails and copy it into your new MainActivity.java file.

We will replace the class MainActivity declaration, member variables, and onCreate(Bundle savedInstanceState) function with the code below:

MainActivity.java (1)

public class MainActivity extends Activity implements AdapterView.OnItemClickListener {

    ListView listView;
    ImageView imageView;
    TextView currentDirText;
    TextView numFilesText;
    Button backButton;
    String rootDir = "DCIM";
    String directoryName = rootDir; // Initialize to rootDirectory
    SimpleAdapter listAdapter;
    int checkInterval = 5000;
    Handler updateHandler;
    boolean viewingList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewingList = true; // Start out viewing the list
        try {
            // Set buttons
            getWindow().setTitleColor(Color.rgb(65, 183, 216));
            backButton = (Button)findViewById(R.id.button1);
            backButton.getBackground().setColorFilter(Color.rgb(65, 183, 216), PorterDuff.Mode.SRC_IN);
            backButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(directoryName.equals(rootDir)) {
                        listRootDirectory();
                    }
                    else {
                        int index = directoryName.lastIndexOf("/");
                        directoryName = directoryName.substring(0, index);
                        listDirectory(directoryName);
                    }
                }
            });
            backButton.setEnabled(false); // Disable in root directory
            listRootDirectory();
        } catch(Exception e) {
            Log.e("ERROR", "ERROR: " + e.toString());
            e.printStackTrace();
        }
        updateHandler = new Handler();
        startUpdate();
    }

We have added a few new member variables to our previous MainActivity class.

  • Line 11:
    We declare int checkInterval, which will set the interval of time (in milliseconds) between status checks of the FlashAir.
  • Line 12:
    We declare Handler updateHandler, which will manage the Runnable that we will implement in the functions below.
  • Line 13:
    We declare boolean viewingList, which will track whether the user is currently viewing a content list or an image.

It is worth noting that we have set the root directory to be the "DCIM" folder (line 8). You do not have to set this as your root directory. Since the "DCIM" folder is the location that most digital cameras store photos, it is set as the root directory for this tutorial.

We will leave the rest of the code in MainActivity.java as is. (This should include the functions to set up the content list.)

Determining the User's Current View

We will add the code that handles status checking and updating to the MainActivity.java file. This code should be included inside class MainActivity with the other functions we have previously written.

If the user is not currently viewing a content list, there is no need to poll the FlashAir device - the content list will get the most current updates when it loads. However, if the user is currently viewing a content list, we will poll the contents of the FlashAir regularly and display any changes.

In order to determine whether the user is viewing a list, we will override a listener function to update the value of the flag variable viewingList declared above (on line 13).

MainActivity.java (2)

    @Override
        public void onWindowFocusChanged(boolean hasFocus) {
            super.onWindowFocusChanged(hasFocus);
            if(hasFocus) {
                viewingList = true;
            }
            else {
                viewingList = false;
            }
        }


    public boolean checkIfListView() {
        // Check if user is viewing a content list
        if(viewingList) {
            return true;
        }
        return false;
    }

The variable flag hasFocus will be true if the screen showing the content list is currently being displayed to the user. Each time the user changes their View, the app will be informed. This will facilitate setting the behavior of the Runnable below.

Setting Up the Update Handler & Content Refresh Task

We will use the following CGI command to get the update status of the FlashAir:

  • command.cgi with op=102
    • The command will look like this: http://flashair/command.cgi?op=102
    • The command will return the following data:
      • 1 if the FlashAir memory has been updated
      • 0 if the memory has not been updated

The CGI command that gets the update status of your FlashAir will only return 1 once. Any future queries before another change is made will return 0, as the FlashAir memory has not been updated since the last query.

To execute this CGI command, we will reuse the FlashAirRequest.java file from Android Tutorial 3: Downloading Content:

The following functions determine the behavior and frequency for auto refreshing the content list.

MainActivity.java (3)

    public Runnable statusChecker = new Runnable() {
        @Override
        public void run() {
            if (checkIfListView() == true) {
                new AsyncTask<String, Void, String>(){
                    @Override
                    protected String doInBackground(String... params) {
                        return FlashAirRequest.getString(params[0]);
                    }
                    @Override
                    protected void onPostExecute(String status) {
                        if(status.equals("1")) {
                            // Fetch current contents of FlashAir and display list
                            listDirectory(directoryName);
                        }
                    }
                }.execute("http://flashair/command.cgi?op=102");
            }
            updateHandler.postDelayed(statusChecker, checkInterval);
        }
    };


    public void startUpdate() {
        statusChecker.run();    
    }


    public void stopUpdate() {
        updateHandler.removeCallbacks(statusChecker);
    }
  • Lines 3-20:
    We set the run() function, which sets the main behavior of the Runnable class.
  • Line 19:
    We have the updateHandler assign the statusChecker to perform its run() function in checkInterval milliseconds. Note that this code is executed inside the run() function itself. This means that so long as the updateHandler does not stop running, each time the statusChecker performs its run() function, it is assigned to run again in checkInterval milliseconds.

Creating the Image Viewing Screen

This file will be identical to the class ImageViewActivity from Android Tutorial 3: Downloading Content. Please refer to that tutorial for an explanation of the implementation.

Sample Code

android_tutorial_05.zip (533KB)

All sample code on this page is licensed under BSD 2-Clause License